package cn.echase.ecare.yinfayun.utils;

import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFDrawing;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.apache.poi.ss.usermodel.ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE;
import static org.apache.poi.ss.util.CellUtil.createCell;

@Slf4j
public class UcExcelUtils {

    private static final ThreadLocal<SimpleDateFormat> fmt = new ThreadLocal<>();

    private static final ThreadLocal<DecimalFormat> df = new ThreadLocal<>();

    private static final Integer DATE_LENGTH = 10;

    private static final String DataValidationError1 = "Excel表格提醒：";

    private static final String DataValidationError2 = "数据不规范，请选择表格下拉列表中的数据！";

    public static final Integer MAX_ROW_SUM = 1048570;

    public static final Integer MAX_ROW_STYLE = 100000;

    /**
     * 导出数据必填
     */
    private List<List<String[]>> dataLists;
    /**
     * sheet名称必填
     */
    private String[] sheetName;
    /**
     * 每个表格的大标题
     */
    private String[] labelName;
    /**
     * 页面响应
     */
    private HttpServletResponse response;
    /**
     * 自定义：单元格合并
     */
    private HashMap regionMap;
    /**
     * 自定义：对每个单元格自定义列宽
     */
    private HashMap mapColumnWidth;
    /**
     * 自定义：每一个单元格样式
     */
    private HashMap styles;
    /**
     * 自定义：固定表头
     */
    private HashMap paneMap;
    /**
     * 自定义：某一行样式
     */
    private HashMap rowStyles;
    /**
     * 自定义：某一列样式
     */
    private HashMap columnStyles;
    /**
     * 自定义：对每个单元格自定义下拉列表
     */
    private HashMap dropDownMap;
    /**
     * 文件名称
     */
    private String fileName = UcONGenerator.getL(null);
    /**
     * 导出本地路径
     */
    private String filePath;

    /**
     * 导出数字格式化：默认是保留六位小数点
     */
    private String numeralFormat = "#.######";

    /**
     * 导出日期格式化：默认是"yyyy-MM-dd"格式
     */
    private String dateFormatStr = "yyyy-MM-dd";
    /**
     * 期望转换后的日期格式：默认是 dateFormatStr
     */
    private String expectDateFormatStr = "yyyy-MM-dd";

    /**
     * 默认列宽大小：默认16
     */
    private Integer defaultColumnWidth = 16;
    /**
     * 默认字体大小：默认12号字体
     */
    private Integer fontSize = 12;

    public UcExcelUtils() {
    }

    public UcExcelUtils(List<List<String[]>> dataLists, String[] sheetName, String[] labelName, HttpServletResponse response, String fileName, String filePath) {
        this.dataLists = dataLists;
        this.sheetName = sheetName;
        this.labelName = labelName;
        this.response = response;
        this.fileName = fileName;
        this.filePath = filePath;
    }

    public UcExcelUtils(List<List<String[]>> dataLists, String[] sheetName, String[] labelName, HttpServletResponse response, HashMap regionMap, HashMap mapColumnWidth, HashMap styles, HashMap paneMap, HashMap rowStyles, HashMap columnStyles, HashMap dropDownMap, String fileName, String filePath, String numeralFormat, String dateFormatStr, String expectDateFormatStr, Integer defaultColumnWidth, Integer fontSize) {
        this.dataLists = dataLists;
        this.sheetName = sheetName;
        this.labelName = labelName;
        this.response = response;
        this.regionMap = regionMap;
        this.mapColumnWidth = mapColumnWidth;
        this.styles = styles;
        this.paneMap = paneMap;
        this.rowStyles = rowStyles;
        this.columnStyles = columnStyles;
        this.dropDownMap = dropDownMap;
        this.fileName = fileName;
        this.filePath = filePath;
        this.numeralFormat = numeralFormat;
        this.dateFormatStr = dateFormatStr;
        this.expectDateFormatStr = expectDateFormatStr;
        this.defaultColumnWidth = defaultColumnWidth;
        this.fontSize = fontSize;
    }

    public static UcExcelUtils initialization() {
        return new UcExcelUtils();
    }

    public static UcExcelUtils initialization(List<List<String[]>> dataLists, String[] sheetName, String[] labelName, HttpServletResponse response, String fileName, String filePath) {
        return new UcExcelUtils(dataLists,sheetName,labelName,response,fileName,filePath);
    }

    public static UcExcelUtils initialization(List<List<String[]>> dataLists, String[] sheetName, String[] labelName, HttpServletResponse response, HashMap regionMap, HashMap mapColumnWidth, HashMap styles, HashMap paneMap, HashMap rowStyles, HashMap columnStyles, HashMap dropDownMap, String fileName, String filePath, String numeralFormat, String dateFormatStr, String expectDateFormatStr, Integer defaultColumnWidth, Integer fontSize) {
        return new UcExcelUtils(dataLists,sheetName,labelName,response,regionMap,mapColumnWidth,styles,paneMap,rowStyles,columnStyles,dropDownMap,fileName,filePath,numeralFormat,dateFormatStr,expectDateFormatStr,defaultColumnWidth,fontSize);
    }

    public static UcExcelUtils initialization(List<List<String[]>> dataLists, String[] sheetName, HttpServletResponse response, String fileName, Integer defaultColumnWidth, Integer fontSize) {
        return new UcExcelUtils(dataLists, sheetName,null, response, null, null, null, null, null, null, null, fileName, null, null, null, null, defaultColumnWidth, fontSize);
    }

    public static UcExcelUtils initialization(List<List<String[]>> dataLists, String[] sheetName, HttpServletResponse response, HashMap dropDownMap, String fileName, Integer defaultColumnWidth, Integer fontSize) {
        return new UcExcelUtils(dataLists, sheetName,null, response, null, null, null, null, null, null, dropDownMap, fileName, null, null, null, null, defaultColumnWidth, fontSize);
    }


    private SimpleDateFormat getDateFormat() {
        SimpleDateFormat format = fmt.get();
        if (format == null) {
            //默认格式日期： "yyyy-MM-dd"
            format = new SimpleDateFormat(expectDateFormatStr, Locale.getDefault());
            fmt.set(format);
        }
        return format;
    }

    public DecimalFormat getDecimalFormat() {
        DecimalFormat format = df.get();
        if (format == null) {
            //默认数字格式： "#.######" 六位小数点
            format = new DecimalFormat(numeralFormat);
            df.set(format);
        }
        return format;
    }

    /**
     * Excel导出：有样式（行、列、单元格样式）、自适应列宽
     * 功能描述: excel 数据导出、导出模板
     * 更新日志:
     * 1.response.reset();注释掉reset，否在会出现跨域错误。[2018-05-18]
     * 2.新增导出多个单元。[2018-08-08]
     * 3.poi官方建议大数据量解决方案：SXSSFWorkbook。[2018-08-08]
     * 4.自定义下拉列表：对每个单元格自定义下拉列表。[2018-08-08]
     * 5.数据遍历方式换成数组(效率较高)。[2018-08-08]
     * 6.可提供模板下载。[2018-08-08]
     * 7.每个表格的大标题[2018-09-14]
     * 8.自定义列宽：对每个单元格自定义列宽[2018-09-18]
     * 9.自定义样式：对每个单元格自定义样式[2018-10-22]
     * 10.自定义单元格合并：对每个单元格合并[2018-10-22]
     * 11.固定表头[2018-10-23]
     * 12.自定义样式：单元格自定义某一列或者某一行样式[2018-11-12]
     * 13.忽略边框(默认是有边框)[2018-11-15]
     * 14.函数式编程换成面向对象编程[2018-12-06-5]
     * 15.单表百万数据量导出时样式设置过多，导致速度慢（行、列、单元格样式暂时控制10万行、超过无样式）[2019-01-30]
     * @return
     */
    public Boolean exportForExcelsOptimize(Boolean file) {
        long startTime = System.currentTimeMillis();
        log.info("=== ===  === :Excel tool class export start run!");
        SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(1000);
        OutputStream outputStream = null;
        SXSSFRow sxssfRow = null;
        try {
            // 设置数据
            setDataList(sxssfWorkbook, sxssfRow, dataLists, regionMap, mapColumnWidth, styles, paneMap, sheetName, labelName, rowStyles, columnStyles, dropDownMap,defaultColumnWidth,fontSize);
            if (file){
                setFileIo(sxssfWorkbook,filePath);
            }else {
                setIo(sxssfWorkbook, outputStream, fileName, sheetName, response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("=== ===  === :Excel tool class export run time:" + (System.currentTimeMillis() - startTime) + " ms!");
        return true;
    }

    /**
     * Excel导出：无样式（行、列、单元格样式）、自适应列宽
     * web 响应（response）
     *
     * @return
     */
    public Boolean exportForExcelsNoStyle(Boolean file) {
        long startTime = System.currentTimeMillis();
        log.info("=== ===  === :Excel tool class export start run!");
        SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(1000);
        OutputStream outputStream = null;
        SXSSFRow sxssfRow = null;
        try {
            setDataListNoStyle(sxssfWorkbook, sxssfRow, dataLists, regionMap, mapColumnWidth, paneMap, sheetName, labelName, dropDownMap,defaultColumnWidth,fontSize);
            if (file){
                setFileIo(sxssfWorkbook,filePath);
            }else {
                setIo(sxssfWorkbook, outputStream, fileName, sheetName, response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("=== ===  === :Excel tool class export run time:" + (System.currentTimeMillis() - startTime) + " ms!");
        return true;
    }

    /**
     * 功能描述:
     * 1.excel 模板数据导入。
     * 2.共用获取Excel表格数据。
     * 3.多单元数据获取。
     * 4.多单元从第几行开始获取数据
     * 5.多单元根据那些列为空来忽略行数据
     * @param book           Workbook对象（不可为空）
     * @param sheetName      多单元数据获取（不可为空）
     * @param indexMap       多单元从第几行开始获取数据，默认从第二行开始获取（可为空，如 hashMapIndex.put(1,3); 第一个表格从第三行开始获取）
     * @param continueRowMap 多单元根据那些列为空来忽略行数据（可为空，如 mapContinueRow.put(1,new Integer[]{1, 3}); 第一个表格从1、3列为空就忽略）
     * @return
     */
    @SuppressWarnings({"deprecation", "rawtypes"})
    public static List<List<LinkedHashMap<String, String>>> importForExcelData(Workbook book, String[] sheetName, HashMap indexMap, HashMap continueRowMap) {
        long startTime = System.currentTimeMillis();
        log.info("=== ===  === :Excel tool class export start run!");
        try {
            List<List<LinkedHashMap<String, String>>> returnDataList = new ArrayList<>();
            for (int k = 0; k <= sheetName.length - 1; k++) {
                //  得到第K个工作表对象、得到第K个工作表中的总行数。
                Sheet sheet = book.getSheet(sheetName[k]);
                int rowCount = sheet.getLastRowNum() + 1;
                Row valueRow = null;
                List<LinkedHashMap<String, String>> rowListValue = new ArrayList<>();
                LinkedHashMap<String, String> cellHashMap = null;
                int irow = 1;
                //  第n个工作表:从开始获取数据、默认第一行开始获取。
                if (indexMap != null && indexMap.get(k + 1) != null) {
                    irow = Integer.valueOf(indexMap.get(k + 1).toString()) - 1;
                }
                //  第n个工作表:数据获取。
                for (int i = irow; i < rowCount; i++) {
                    valueRow = sheet.getRow(i);
                    if (valueRow == null) {
                        continue;
                    }
                    //  第n个工作表:从开始列忽略数据、为空就跳过。
                    if (continueRowMap != null && continueRowMap.get(k + 1) != null) {
                        int continueRowCount = 0;
                        Integer[] continueRow = (Integer[]) continueRowMap.get(k + 1);
                        for (int w = 0; w <= continueRow.length - 1; w++) {
                            Cell valueRowCell = valueRow.getCell(continueRow[w] - 1);
                            if (valueRowCell == null || isBlank(valueRowCell.toString())) {
                                continueRowCount = continueRowCount + 1;
                            }
                        }
                        if (continueRowCount == continueRow.length) {
                            continue;
                        }
                    }
                    cellHashMap = new LinkedHashMap<>();
                    //  第n个工作表:获取列数据。
                    for (int j = 0; j < valueRow.getLastCellNum(); j++) {
                        cellHashMap.put(Integer.toString(j), getCellVal(valueRow.getCell(j)));
                    }
                    if (cellHashMap.size() > 0) {
                        rowListValue.add(cellHashMap);
                    }
                }
                returnDataList.add(rowListValue);
            }
            log.info("=== ===  === :Excel tool class export run time:" + (System.currentTimeMillis() - startTime) + " ms!");
            return returnDataList;
        } catch (Exception e) {
            log.debug("=== ===  === :Andyczy ExcelUtils Exception Message：Excel tool class export exception !");
            e.printStackTrace();
            return null;
        }
    }


    /**
     * response 响应
     *
     * @param sxssfWorkbook
     * @param outputStream
     * @param fileName
     * @param sheetName
     * @param response
     * @throws Exception
     */
    private static void setIo(SXSSFWorkbook sxssfWorkbook, OutputStream outputStream, String fileName, String[] sheetName, HttpServletResponse response) throws Exception {
        log.info("=== ===  === :setIo ms!");
        try {
            if (response != null) {
                log.info("=== ===  === :response null ms!");
                //默认Excel名称
                response.setHeader("Content-Disposition", "attachment;fileName="+"test.xls");
                response.setHeader("Content-Type", "application/force-download");
                response.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName == null ? sheetName[0] : fileName, "utf8") + ".xlsx");
                response.flushBuffer();
                outputStream = response.getOutputStream();
            }
            writeAndColse(sxssfWorkbook, outputStream);
        } catch (Exception e) {
            e.getSuppressed();
        }
    }

    /**
     * 输出本地地址
     *
     * @param sxssfWorkbook
     * @param filePath
     * @throws Exception
     */
    private static void setFileIo(SXSSFWorkbook sxssfWorkbook, String filePath) throws Exception {
        OutputStream outputStream = null;
        try {
            if (filePath != null) {
                outputStream = new FileOutputStream(filePath);
                if (outputStream != null) {
                    sxssfWorkbook.write(outputStream);
                    sxssfWorkbook.dispose();
                    outputStream.flush();
                    outputStream.close();
                }
            }
        } catch (Exception e) {
            e.getSuppressed();
        }
    }




    /**
     * 功能描述: 获取Excel单元格中的值并且转换java类型格式
     *
     * @param cell
     * @return
     */
    private static String getCellVal(Cell cell) {
        String val = null;
        if (cell != null) {
            CellType cellType = cell.getCellType();
            switch (cellType) {
                case NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell)) {
                        val = UcExcelUtils.initialization().getDateFormat().format(cell.getDateCellValue());
                    } else {
                        val = UcExcelUtils.initialization().getDecimalFormat().format(cell.getNumericCellValue());
                    }
                    break;
                case STRING:
                    if (cell.getStringCellValue().trim().length() >= DATE_LENGTH && verificationDate(cell.getStringCellValue(), UcExcelUtils.initialization().dateFormatStr)) {
                        val = strToDateFormat(cell.getStringCellValue(), UcExcelUtils.initialization().dateFormatStr, UcExcelUtils.initialization().expectDateFormatStr);
                    } else {
                        val = cell.getStringCellValue();
                    }
                    break;
                case BOOLEAN:
                    val = String.valueOf(cell.getBooleanCellValue());
                    break;
                case BLANK:
                    val = cell.getStringCellValue();
                    break;
                case ERROR:
                    val = "错误";
                    break;
                case FORMULA:
                    try {
                        val = String.valueOf(cell.getStringCellValue());
                    } catch (IllegalStateException e) {
                        val = String.valueOf(cell.getNumericCellValue());
                    }
                    break;
                default:
                    val = cell.getRichStringCellValue() == null ? null : cell.getRichStringCellValue().toString();
            }
        } else {
            val = "";
        }
        return val;
    }

    /**
     * 设置数据：有样式（行、列、单元格样式）
     *
     * @param wb
     * @param sxssfRow
     * @param dataLists
     * @param regionMap
     * @param columnMap
     * @param styles
     * @param paneMap
     * @param sheetName
     * @param labelName
     * @param rowStyles
     * @param columnStyles
     * @param dropDownMap
     * @throws Exception
     */
    public static void setDataList(SXSSFWorkbook wb, SXSSFRow sxssfRow, List<List<String[]>> dataLists,
                                   HashMap regionMap, HashMap columnMap, HashMap styles, HashMap paneMap,
                                   String[] sheetName, String[] labelName, HashMap rowStyles, HashMap columnStyles, HashMap dropDownMap, Integer defaultColumnWidth,Integer fontSize) throws Exception {
        if (dataLists == null) {
            log.debug("=== ===  === :Andyczy ExcelUtils Exception Message：Export data(type:List<List<String[]>>) cannot be empty!");
        }
        if (sheetName == null) {
            log.debug("=== ===  === :Andyczy ExcelUtils Exception Message：Export sheet(type:String[]) name cannot be empty!");
        }
        int k = 0;
        for (List<String[]> listRow : dataLists) {
            SXSSFSheet sxssfSheet = wb.createSheet();
            sxssfSheet.setDefaultColumnWidth(defaultColumnWidth);
            wb.setSheetName(k, sheetName[k]);
            CellStyle cellStyle = wb.createCellStyle();
            CellStyle integerCellStyle = wb.createCellStyle();
            CellStyle doubleCellStyle = wb.createCellStyle();
            XSSFFont font = (XSSFFont) wb.createFont();
            SXSSFDrawing sxssfDrawing = sxssfSheet.createDrawingPatriarch();

            int jRow = 0;

            //  自定义：大标题（看该方法说明）。
            jRow = setLabelName(jRow, k, wb, labelName, sxssfRow, sxssfSheet, listRow);

            //  自定义：每个表格固定表头（看该方法说明）。
            Integer pane = 1;
            if (paneMap != null && paneMap.get(k + 1) != null) {
                pane = (Integer) paneMap.get(k + 1) + (labelName != null ? 1 : 0);
                createFreezePane(sxssfSheet, pane);
            }
            //  自定义：每个单元格自定义合并单元格：对每个单元格自定义合并单元格（看该方法说明）。
            if (regionMap != null) {
                setMergedRegion(sxssfSheet, (ArrayList<Integer[]>) regionMap.get(k + 1));
            }
            //  自定义：每个单元格自定义下拉列表：对每个单元格自定义下拉列表（看该方法说明）。
            if (dropDownMap != null) {
                setDataValidation(sxssfSheet, (List<String[]>) dropDownMap.get(k + 1), listRow.size());
            }
            //  自定义：每个表格自定义列宽：对每个单元格自定义列宽（看该方法说明）。
            if (columnMap != null) {
                setColumnWidth(sxssfSheet, (HashMap) columnMap.get(k + 1));
            }
            setBorder(integerCellStyle, true);
            setBorder(doubleCellStyle, true);
            //  默认样式。
            setStyle(cellStyle, font,fontSize);
            CellStyle cell_style = null;
            CellStyle row_style = null;
            CellStyle column_style = null;
            //  写入小标题与数据。
            Integer SIZE = listRow.size() < MAX_ROW_SUM ? listRow.size() : MAX_ROW_SUM;
            Integer MAXSYTLE = listRow.size() < MAX_ROW_STYLE ? listRow.size() : MAX_ROW_STYLE;
            for (int i = 0; i < SIZE; i++) {
                sxssfRow = sxssfSheet.createRow(jRow);
                for (int j = 0; j < listRow.get(i).length; j++) {
                    //  样式过多会导致GC内存溢出！
                    try {
                        Cell cell = null;
                        if (patternIsImg(listRow.get(i)[j])) {
                            cell = createCell(sxssfRow, j, " ");
                            drawPicture(wb, sxssfDrawing, listRow.get(i)[j], j, jRow);
                            cell.setCellStyle(cellStyle);
                        }
                        else if (isNumeric(listRow.get(i)[j])) {
                            if (listRow.get(i)[j].startsWith("0")) {
                                // 0开头的可能是证件号，0不能去掉
                                DataFormat df = wb.createDataFormat();
                                cellStyle.setDataFormat(df.getFormat("@"));
                                cell = createCell(sxssfRow, j, listRow.get(i)[j]);
                                cell.setCellStyle(cellStyle);
                            }else {
                                cell = createCell(sxssfRow, j, listRow.get(i)[j]);
                                DataFormat df = wb.createDataFormat();
                                if (listRow.get(i)[j].matches("^[-\\+]?[\\d]*$")) {
                                    integerCellStyle.setDataFormat(df.getFormat("0_ "));//数据格式只显示整数
                                    cell.setCellStyle(integerCellStyle);
                                    cell.setCellValue(Integer.parseInt(listRow.get(i)[j]));
                                } else{
                                    doubleCellStyle.setDataFormat(df.getFormat("0.00_ "));//保留两位小数点
                                    cell.setCellStyle(doubleCellStyle);
                                    cell.setCellValue(Double.parseDouble(listRow.get(i)[j]));
                                }
                            }
                        }
                        else {
                            cell = createCell(sxssfRow, j, listRow.get(i)[j]);
                            cell.setCellStyle(cellStyle);
                        }
                        //  自定义：每个表格每一列的样式（看该方法说明）。
                        if (columnStyles != null && jRow >= pane && i <= MAXSYTLE) {
                            setExcelRowStyles(cell, wb, sxssfRow, (List) columnStyles.get(k + 1), j);
                        }
                        //  自定义：每个表格每一行的样式（看该方法说明）。
                        if (rowStyles != null && i <= MAXSYTLE) {
                            setExcelRowStyles(cell, wb, sxssfRow, (List) rowStyles.get(k + 1), jRow);
                        }
                        //  自定义：每一个单元格样式（看该方法说明）。
                        if (styles != null && i <= MAXSYTLE) {
                            setExcelStyles(cell, wb, sxssfRow, (List<List<Object[]>>) styles.get(k + 1), j, i);
                        }
                    } catch (Exception e) {
                        log.debug("=== ===  === :Andyczy ExcelUtils Exception Message：The maximum number of cell styles was exceeded. You can define up to 4000 styles!");
                    }
                }
                jRow++;
            }
            k++;
        }
    }


    /**
     * @param cell         Cell对象。
     * @param wb           SXSSFWorkbook对象。
     * @param fontSize     字体大小。
     * @param bold         是否加粗。
     * @param center       是否左右上下居中。
     * @param isBorder     是否忽略边框
     * @param leftBoolean  左对齐
     * @param rightBoolean 右对齐
     * @param height       行高
     */
    public static void setExcelStyles(Cell cell, SXSSFWorkbook wb, SXSSFRow sxssfRow, Integer fontSize, Boolean bold, Boolean center, Boolean isBorder, Boolean leftBoolean,
                                      Boolean rightBoolean, Integer fontColor, Integer height) {
        CellStyle cellStyle = cell.getRow().getSheet().getWorkbook().createCellStyle();
        //保证了既可以新建一个CellStyle，又可以不丢失原来的CellStyle 的样式
        cellStyle.cloneStyleFrom(cell.getCellStyle());
        //左右居中、上下居中
        if (center != null && center) {
            cellStyle.setAlignment(HorizontalAlignment.CENTER);
            cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        }
        //右对齐
        if (rightBoolean != null && rightBoolean) {
            cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            cellStyle.setAlignment(HorizontalAlignment.RIGHT);
        }
        //左对齐
        if (leftBoolean != null && leftBoolean) {
            cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            cellStyle.setAlignment(HorizontalAlignment.LEFT);
        }
        //是否忽略边框
        if (isBorder != null && isBorder) {
            setBorderColor(cellStyle, isBorder);
        }
        //设置单元格字体样式
        XSSFFont font = (XSSFFont) wb.createFont();
        if (bold != null && bold) {
            font.setBold(bold);
        }
        //行高
        if (height != null) {
            sxssfRow.setHeight((short) (height * 2));
        }
        font.setFontName("宋体");
        font.setFontHeight(fontSize == null ? 12 : fontSize);
        cellStyle.setFont(font);
        //   点击可查看颜色对应的值： BLACK(8), WHITE(9), RED(10),
        font.setColor(IndexedColors.fromInt(fontColor == null ? 8 : fontColor).index);
        cell.setCellStyle(cellStyle);
    }


    public static void setExcelRowStyles(Cell cell, SXSSFWorkbook wb, SXSSFRow sxssfRow, List<Object[]> rowstyleList, int rowIndex) {
        if (rowstyleList != null && rowstyleList.size() > 0) {
            Integer[] rowstyle = (Integer[]) rowstyleList.get(1);
            for (int i = 0; i < rowstyle.length; i++) {
                if (rowIndex == rowstyle[i]) {
                    Boolean[] bool = (Boolean[]) rowstyleList.get(0);
                    Integer fontColor = null;
                    Integer fontSize = null;
                    Integer height = null;
                    //当有设置颜色值 、字体大小、行高才获取值
                    if (rowstyleList.size() >= 3) {
                        int leng = rowstyleList.get(2).length;
                        if (leng >= 1) {
                            fontColor = (Integer) rowstyleList.get(2)[0];
                        }
                        if (leng >= 2) {
                            fontSize = (Integer) rowstyleList.get(2)[1];
                        }
                        if (leng >= 3) {
                            height = (Integer) rowstyleList.get(2)[2];
                        }
                    }
                    setExcelStyles(cell, wb, sxssfRow, fontSize, Boolean.valueOf(bool[3]), Boolean.valueOf(bool[0]), Boolean.valueOf(bool[4]), Boolean.valueOf(bool[2]), Boolean.valueOf(bool[1]), fontColor, height);
                }
            }
        }
    }

    /**
     * 画图片
     *
     * @param wb
     * @param sxssfDrawing
     * @param pictureUrl
     * @param rowIndex
     */
    private static void drawPicture(SXSSFWorkbook wb, SXSSFDrawing sxssfDrawing, String pictureUrl, int colIndex, int rowIndex) {
        //rowIndex代表当前行
        try {
            if (pictureUrl != null) {
                URL url = new URL(pictureUrl);
                //打开链接
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5 * 1000);
                InputStream inStream = conn.getInputStream();
                byte[] data = readInputStream(inStream);
                //设置图片大小，
                XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 50, 50, colIndex, rowIndex, colIndex + 1, rowIndex + 1);
                anchor.setAnchorType(DONT_MOVE_AND_RESIZE);
                sxssfDrawing.createPicture(anchor, wb.addPicture(data, XSSFWorkbook.PICTURE_TYPE_JPEG));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 是否是图片
     *
     * @param str
     * @return
     */
    public static Boolean patternIsImg(String str) {
        String reg = ".+(.JPEG|.jpeg|.JPG|.jpg|.png|.gif)$";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(str);
        Boolean temp = matcher.find();
        return temp;
    }


    /**
     * 是否数字
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        if (null == str || "".equals(str) || str.length() > 18) {
            return false;
        }
        String regx = "[+-]*\\d+\\.?\\d*[Ee]*[+-]*\\d+";
        Pattern pattern = Pattern.compile(regx);
        boolean isNumber = pattern.matcher(str).matches();
        if (isNumber) {
            return isNumber;
        }
        regx = "^[-\\+]?[.\\d]*$";
        pattern = Pattern.compile(regx);
        return pattern.matcher(str).matches();
    }

    /**
     * @param inStream
     * @return
     * @throws Exception
     */
    private static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        //创建一个Buffer字符串
        byte[] buffer = new byte[1024];
        //每次读取的字符串长度，如果为-1，代表全部读取完毕
        int len = 0;
        //使用一个输入流从buffer里把数据读取出来
        while ((len = inStream.read(buffer)) != -1) {
            //用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
            outStream.write(buffer, 0, len);
        }
        //关闭输入流
        inStream.close();
        //把outStream里的数据写入内存
        return outStream.toByteArray();
    }


    /**
     * 自定义：大标题
     *
     * @param jRow
     * @param k
     * @param wb
     * @param labelName
     * @param sxssfRow
     * @param sxssfSheet
     * @param listRow
     * @return
     */
    private static int setLabelName(Integer jRow, Integer k, SXSSFWorkbook wb, String[] labelName, SXSSFRow sxssfRow, SXSSFSheet sxssfSheet, List<String[]> listRow) {

        if (labelName != null) {
            //  自定义：大标题和样式。参数说明：new String[]{"表格数据一", "表格数据二", "表格数据三"}
            sxssfRow = sxssfSheet.createRow(0);
            Cell cell = createCell(sxssfRow, 0, labelName[k]);
            setMergedRegion(sxssfSheet, 0, 0, 0, listRow.get(0).length - 1);
            setLabelStyles(wb, cell, sxssfRow);
            jRow = 1;
        }
        return jRow;
    }

    /**
     * 设置数据：无样式（行、列、单元格样式）
     *
     * @param wb
     * @param sxssfRow
     * @param dataLists
     * @param regionMap
     * @param columnMap
     * @param paneMap
     * @param sheetName
     * @param labelName
     * @param dropDownMap
     * @throws Exception
     */
    public static void setDataListNoStyle(SXSSFWorkbook wb, SXSSFRow sxssfRow, List<List<String[]>> dataLists, HashMap regionMap,
                                          HashMap columnMap, HashMap paneMap, String[] sheetName, String[] labelName, HashMap dropDownMap,Integer defaultColumnWidth,Integer fontSize) throws Exception {
        if (dataLists == null) {
            log.debug("=== ===  === :Andyczy ExcelUtils Exception Message：Export data(type:List<List<String[]>>) cannot be empty!");
        }
        if (sheetName == null) {
            log.debug("=== ===  === :Andyczy ExcelUtils Exception Message：Export sheet(type:String[]) name cannot be empty!");
        }
        int k = 0;
        for (List<String[]> listRow : dataLists) {
            SXSSFSheet sxssfSheet = wb.createSheet();
            sxssfSheet.setDefaultColumnWidth(defaultColumnWidth);
            wb.setSheetName(k, sheetName[k]);
            CellStyle cellStyle = wb.createCellStyle();
            XSSFFont font = (XSSFFont) wb.createFont();
            int jRow = 0;
            //  自定义：大标题（看该方法说明）。
            jRow = setLabelName(jRow, k, wb, labelName, sxssfRow, sxssfSheet, listRow);
            //  自定义：每个表格固定表头（看该方法说明）。
            Integer pane = 1;
            if (paneMap != null && paneMap.get(k + 1) != null) {
                pane = (Integer) paneMap.get(k + 1) + (labelName != null ? 1 : 0);
                createFreezePane(sxssfSheet, pane);
            }
            //  自定义：每个单元格自定义合并单元格：对每个单元格自定义合并单元格（看该方法说明）。
            if (regionMap != null) {
                setMergedRegion(sxssfSheet, (ArrayList<Integer[]>) regionMap.get(k + 1));
            }
            //  自定义：每个单元格自定义下拉列表：对每个单元格自定义下拉列表（看该方法说明）。
            if (dropDownMap != null) {
                setDataValidation(sxssfSheet, (List<String[]>) dropDownMap.get(k + 1), listRow.size());
            }
            //  自定义：每个表格自定义列宽：对每个单元格自定义列宽（看该方法说明）。
            if (columnMap != null) {
                setColumnWidth(sxssfSheet, (HashMap) columnMap.get(k + 1));
            }
            //  默认样式。
            setStyle(cellStyle, font,fontSize);
            //  写入小标题与数据。
            Integer SIZE = listRow.size() < MAX_ROW_SUM ? listRow.size() : MAX_ROW_SUM;
            for (int i = 0; i < SIZE; i++) {
                sxssfRow = sxssfSheet.createRow(jRow);
                for (int j = 0; j < listRow.get(i).length; j++) {
                    Cell cell = createCell(sxssfRow, j, listRow.get(i)[j]);
                    cell.setCellStyle(cellStyle);
                }
                jRow++;
            }
            k++;
        }
    }


    public static void writeAndColse(SXSSFWorkbook sxssfWorkbook, OutputStream outputStream) throws Exception {
        try {
            if (outputStream != null) {
                sxssfWorkbook.write(outputStream);
                sxssfWorkbook.dispose();
                outputStream.flush();
                outputStream.close();
            }
        } catch (Exception e) {
            System.out.println(" Andyczy ExcelUtils Exception Message：Output stream is not empty !");
            e.getSuppressed();
        }
    }

    /**
     * 功能描述：所有自定义单元格样式
     *
     * @param cell
     * @param wb
     * @param styles
     */
    public static void setExcelStyles(Cell cell, SXSSFWorkbook wb, SXSSFRow sxssfRow, List<List<Object[]>> styles, int cellIndex, int rowIndex) {
        if (styles != null) {
            for (int z = 0; z < styles.size(); z++) {
                List<Object[]> stylesList = styles.get(z);
                if (stylesList != null) {
                    //样式
                    Boolean[] bool = (Boolean[]) stylesList.get(0);
                    //颜色和字体
                    Integer fontColor = null;
                    Integer fontSize = null;
                    Integer height = null;
                    //当有设置颜色值 、字体大小、行高才获取值
                    if (stylesList.size() >= 2) {
                        int leng = stylesList.get(1).length;
                        if (leng >= 1) {
                            fontColor = (Integer) stylesList.get(1)[0];
                        }
                        if (leng >= 2) {
                            fontSize = (Integer) stylesList.get(1)[1];
                        }
                        if (leng >= 3) {
                            height = (Integer) stylesList.get(1)[2];
                        }
                    }
                    //第几行第几列
                    for (int m = 2; m < stylesList.size(); m++) {
                        Integer[] str = (Integer[]) stylesList.get(m);
                        if (cellIndex + 1 == (str[1]) && rowIndex + 1 == (str[0])) {
                            setExcelStyles(cell, wb, sxssfRow, fontSize, Boolean.valueOf(bool[3]), Boolean.valueOf(bool[0]), Boolean.valueOf(bool[4]), Boolean.valueOf(bool[2]), Boolean.valueOf(bool[1]), fontColor, height);
                        }
                    }
                }
            }
        }
    }


    /**
     * 大标题样式
     *
     * @param wb
     * @param cell
     * @param sxssfRow
     */
    public static void setLabelStyles(SXSSFWorkbook wb, Cell cell, SXSSFRow sxssfRow) {
        CellStyle cellStyle = wb.createCellStyle();
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        sxssfRow.setHeight((short) (399 * 2));
        XSSFFont font = (XSSFFont) wb.createFont();
        font.setFontName("宋体");
        font.setFontHeight(16);
        cellStyle.setFont(font);
        cell.setCellStyle(cellStyle);
    }

    /**
     * 默认样式
     *
     * @param cellStyle
     * @param font
     * @return
     * @Parm
     */
    public static void setStyle(CellStyle cellStyle, XSSFFont font, Integer fontSize) {
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        font.setFontName("宋体");
        cellStyle.setFont(font);
        font.setFontHeight(fontSize);
        setBorder(cellStyle, true);
    }


    /**
     * 判断字符串是否为空
     *
     * @param str
     * @return
     */
    public static boolean isBlank(String str) {
        int strLen;
        if (str != null && (strLen = str.length()) != 0) {
            for (int i = 0; i < strLen; ++i) {
                if (!Character.isWhitespace(str.charAt(i))) {
                    return false;
                }
            }
            return true;
        } else {
            return true;
        }
    }

    /**
     * 功能描述: 锁定行（固定表头）
     *
     * @param sxssfSheet
     * @param row
     */
    public static void createFreezePane(SXSSFSheet sxssfSheet, Integer row) {
        if (row != null && row > 0) {
            sxssfSheet.createFreezePane(0, row, 0, 1);
        }
    }

    /**
     * 功能描述: 自定义列宽
     *
     * @param sxssfSheet
     * @param map
     */
    public static void setColumnWidth(SXSSFSheet sxssfSheet, HashMap map) {
        if (map != null) {
            Iterator iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                Object key = entry.getKey();
                Object val = entry.getValue();
                sxssfSheet.setColumnWidth((int) key, (int) val * 512);
            }
        }
    }


    /**
     * 功能描述: excel 合并单元格
     *
     * @param sheet
     * @param rowColList
     */
    public static void setMergedRegion(SXSSFSheet sheet, ArrayList<Integer[]> rowColList) {
        if (rowColList != null && rowColList.size() > 0) {
            for (int i = 0; i < rowColList.size(); i++) {
                Integer[] str = rowColList.get(i);
                if (str.length > 0 && str.length == 4) {
                    Integer firstRow = str[0];
                    Integer lastRow = str[1];
                    Integer firstCol = str[2];
                    Integer lastCol = str[3];
                    setMergedRegion(sheet, firstRow, lastRow, firstCol, lastCol);
                }
            }
        }
    }

    /**
     * 功能描述: 合并单元格
     *
     * @param sheet
     * @param firstRow
     * @param lastRow
     * @param firstCol
     * @param lastCol
     */
    public static void setMergedRegion(SXSSFSheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) {
        sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));
    }


    /**
     * 功能描述:下拉列表
     *
     * @param sheet
     * @param dropDownListData
     * @param dataListSize
     */
    public static void setDataValidation(SXSSFSheet sheet, List<String[]> dropDownListData, int dataListSize) {
        if (dropDownListData.size() > 0) {
            for (int col = 0; col < dropDownListData.get(0).length; col++) {
                Integer colv = Integer.parseInt(dropDownListData.get(0)[col]);
                setDataValidation(sheet, dropDownListData.get(col + 1), 1, dataListSize < 100 ? 500 : dataListSize, colv, colv);
            }
        }
    }


    /**
     * 功能描述:下拉列表
     *
     * @param xssfWsheet
     * @param list
     * @param firstRow
     * @param lastRow
     * @param firstCol
     * @param lastCol
     */
    public static void setDataValidation(SXSSFSheet xssfWsheet, String[] list, Integer firstRow, Integer lastRow, Integer firstCol, Integer lastCol) {
        DataValidationHelper helper = xssfWsheet.getDataValidationHelper();
        CellRangeAddressList addressList = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
        DataValidationConstraint constraint = helper.createExplicitListConstraint(list);
        DataValidation dataValidation = helper.createValidation(constraint, addressList);
        dataValidation.createErrorBox(DataValidationError1, DataValidationError2);
        //  处理Excel兼容性问题
        if (dataValidation instanceof XSSFDataValidation) {
            dataValidation.setSuppressDropDownArrow(true);
            dataValidation.setShowErrorBox(true);
        } else {
            dataValidation.setSuppressDropDownArrow(false);
        }
        xssfWsheet.addValidationData(dataValidation);
    }

    /**
     * 功能描述：设置边框
     *
     * @param cellStyle
     * @param isBorder
     */
    public static void setBorder(CellStyle cellStyle, Boolean isBorder) {
        if (isBorder) {
            cellStyle.setBorderBottom(BorderStyle.THIN);
            cellStyle.setBorderLeft(BorderStyle.THIN);
            cellStyle.setBorderTop(BorderStyle.THIN);
            cellStyle.setBorderRight(BorderStyle.THIN);
        } else {
            //添加白色背景，统一设置边框后但不能选择性去掉，只能通过背景覆盖达到效果。
            cellStyle.setBottomBorderColor(IndexedColors.WHITE.getIndex());
            cellStyle.setLeftBorderColor(IndexedColors.WHITE.getIndex());
            cellStyle.setRightBorderColor(IndexedColors.WHITE.getIndex());
            cellStyle.setTopBorderColor(IndexedColors.WHITE.getIndex());
        }
    }

    public static void setBorderColor(CellStyle cellStyle, Boolean isBorder) {
        if (isBorder) {
            //添加白色背景，统一设置边框后但不能选择性去掉，只能通过背景覆盖达到效果。
            cellStyle.setBottomBorderColor(IndexedColors.WHITE.getIndex());
            cellStyle.setLeftBorderColor(IndexedColors.WHITE.getIndex());
            cellStyle.setRightBorderColor(IndexedColors.WHITE.getIndex());
            cellStyle.setTopBorderColor(IndexedColors.WHITE.getIndex());
        }
    }


    /**
     * 验证是否是日期
     *
     * @param strDate
     * @return
     */
    public static boolean verificationDate(String strDate, String style) {
        Date date = null;
        if (style == null) {
            style = "yyyy-MM-dd";
        }
        SimpleDateFormat formatter = new SimpleDateFormat(style);
        try {
            formatter.parse(strDate);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public static String strToDateFormat(String strDate, String style, String expectDateFormatStr) {
        Date date = null;
        if (style == null) {
            style = "yyyy-MM-dd";
        }
        // 日期字符串转成date类型
        SimpleDateFormat formatter = new SimpleDateFormat(style);
        try {
            date = formatter.parse(strDate);
        } catch (Exception e) {
            return null;
        }
        // 转成指定的日期格式
        SimpleDateFormat sdf = new SimpleDateFormat(expectDateFormatStr == null ? style : expectDateFormatStr);
        String str = sdf.format(date);
        return str;
    }



    /**
     * 1、参数 dataLists
     *
     *    @Override
     *    public List<List<String[]>> exportData(String deviceNo,String snExt,Integer parentInstId,String startDate, String endDate){
     *        List<List<String[]>> dataLists = new ArrayList<>();
     *        List<String[]> oneList = new ArrayList<>();  // 表格一数据
     *        PageInfo<BillInfo> pagePageInfo = getBillPage(1,10000,null,snExt,deviceNo,parentInstId,startDate,endDate);
     *        String[] valueString = null;
     *
     *        String[] headers = {"序号","标题一","标题一","标题二","标题三","标题四","标题五","标题六"};
     *
     *        oneList.add(headers);
     *
     *        for (int i = 0; i < pagePageInfo.getList().size(); i++) {
     *            valueString = new String[]{(i + 1) + "", pagePageInfo.getList().get(i).getSnExt(),
     *                    getNeededDateStyle(pagePageInfo.getList().get(i).getPayTime(),"yyyy-MM-dd hh:mm:ss"),
     *                    pagePageInfo.getList().get(i).getInstName(),pagePageInfo.getList().get(i).getStatisticsPrice()+"",
     *                    pagePageInfo.getList().get(i).getDeviceNo(),
     *                    pagePageInfo.getList().get(i).getWarning()==1?"是":"否"};
     *            oneList.add(valueString);
     *        }
     *
     *        List<String[]> twoList = new ArrayList<>();  // 表格二数据格式与表一相同
     *
     *
     *        listArray.add(oneList);   // 多个表格导出就是多个sheet
     *        listArray.add(twoList);   // 多个表格导出就是多个sheet
     *        return dataLists;
     *    }
     * 2、参数：sheetName(每个sheet名称)、fileName(导出Excel文件名称)、labelName(每个sheet大标题，与sheetName格式一样)
     *
     *    需注意的是：如果是多表格导出、sheetName也要是多个值！
     *    如上面有两个数据导出：
     *    String[] sheetNameList = new String[]{"表格一数据","表格二数据"};
     *    excelUtils.setSheetName(sheetNameList);
     * 2、自定义列宽：参数 mapColumnWidth
     *
     *    HashMap<Integer, HashMap<Integer, Integer>> mapColumnWidth = new HashMap<>();
     *    HashMap<Integer, Integer> mapColumn = new HashMap<>();
     *    //第一列、宽度为 3[3的大小就是两个12号字体刚刚好的列宽]（注意：excel从零行开始数）
     *    mapColumn.put(0, 3);
     *    mapColumn.put(1, 20);
     *    mapColumn.put(2, 15);
     *    //第一个单元格列宽
     *    mapColumnWidth.put(1, mapColumn);
     * 3、自定义固定表头：参数 paneMap
     *
     *    HashMap paneMap = new HashMap();
     *    //第一个表格、第一行开始固定表头
     *    paneMap.put(1, 1);
     * 4、自定义合并单元格：参数 regionMap
     *
     *     HashMap regionMap = new HashMap();
     *     //合并单元格-代表起始行号，终止行号， 起始列号，终止列号进行合并。
     *     ArrayList<Integer[]> sheet1 = new ArrayList<>();
     *
     *     //代表起始行号，终止行号， 起始列号，终止列号进行合并。（注意：excel从零行开始数）
     *     sheet1.add(new Integer[]{1, 1, 0, 10});
     *     sheet1.add(new Integer[]{2, 3, 1, 1});
     *     //第一个表格设置。
     *     regionMap.put(1, sheet1);
     * 5、自定义下拉列表值：参数 dropDownMap
     *
     *    HashMap dropDownMap = new HashMap();
     *    List<String[]> dropList = new ArrayList<>();
     *    //必须放第一：设置下拉列表的列（excel从零行开始数）
     *    String[] sheetDropData = new String[]{"1", "2" };
     *
     *    //下拉的值放在 sheetDropData 后面。
     *    String[] sex = {"男,女"};                      // 第一列显示的值
     *    String[] city = {"北京","山东","海南","湖南"};  // 第二列显示的值
     *    dropList.add(sheetDropData);
     *    dropList.add(sex);
     *    dropList.add(city);
     *    //第一个表格设置。
     *    dropDownMap.put(1, dropList);
     * 6、自定义每个(sheet)表格第几行或者是第几列的样式：参数 rowStyles / columnStyles (默认带边框)
     *
     *     参数说明：
     *     HashMap columnStyles = new HashMap();
     *     List list = new ArrayList();
     *
     *     //1、样式（是否居中？，是否右对齐？，是否左对齐？， 是否加粗？，是否忽略边框？ ）
     *     list.add(new Boolean[]{true, false, false, false, true});
     *
     *     //2、第几行或者是第几列（注意：excel从零行开始数）
     *     list.add(new Integer[]{1, 3});
     *
     *     //3、颜色（8是黑色、10红色等） 、字体、行高（可不设置）
     *     list.add(new Integer[]{10,14,null});
     *
     *     //第一表格
     *     columnStyles.put(1,list);
     * 7、自定义每一个单元格样式：参数 styles (默认带边框)
     *
     *    参数说明：
     *    HashMap styles = new HashMap();
     *    List< List<Object[]>> stylesList = new ArrayList<>();
     *    List<Object[]> stylesObj = new ArrayList<>();
     *    List<Object[]> stylesObjTwo = new ArrayList<>();
     *
     *    //1、样式一（是否居中？，是否右对齐？，是否左对齐？， 是否加粗？，是否忽略边框？ ）
     *    stylesObj.add(new Boolean[]{true, false, false, false, true});
     *
     *    //1、颜色（8是黑色、10红色等） 、字体、行高（可不设置）（必须放第二）
     *    stylesObj.add(new Integer[]{10, 12});
     *
     *    //1、第五行、第一列（注意：excel从一开始算）
     *    stylesObj.add(new Integer[]{5, 1});
     *    stylesObj.add(new Integer[]{6, 1});
     *
     *    //样式二
     *    //样式三
     *
     *    stylesList.add(stylesObj);
     *    //第一个表格所有自定义单元格样式
     *    styles.put(1, stylesList);
     * 二、导入配置
     * 1、(第几行开始获取数据) 参数 indexMap
     *
     *    参数说明：多单元从第几行开始获取数据，默认从第二行开始获取（可为空)
     *    HashMap hashMapIndex = new HashMap();
     *    hashMapIndex.put(1,3);  //  第一个表格从第三行开始获取
     * 2、导入配置：(列为空来忽略行数据) 参数 continueRowMap
     *
     *    参数说明：多单元根据那些列为空来忽略行数据（可为空)
     *    HashMap mapContinueRow = new HashMap();
     *    // 第一个表格第1、3列为空就忽略这行数据
     *    mapContinueRow.put(1,new Integer[]{1, 3});
     * 3、数据格式 导入时间格式（默认：yyyy-MM-dd） 导入数字保留的小数点（默认：#.###### 六位）
     *
     *     ExcelUtils excelUtils = ExcelUtils.initialization();
     *     // (可为空、期望保留小数的位数，如（#.####）保留四位。
     *     excelUtils.setNumeralFormat("#.####");
     *
     *     // (可为空、将转换的时间格式)
     *     // (poi 只接受无中文的日期格式、如果你想转换别的格式，这个参数要和导入表中日期格式类似，如表格中为：2019年02月14日 12时12分)。
     *     excelUtils.setDateFormatStr("yyyy年MM月dd日 HH时mm分");
     *
     *     //(可为空、期望转换后的日期格式)
     *     excelUtils.setExpectDateFormatStr("yyyy-MM-dd HH-mm");  // (可为空、默认的值是：dateFormatStr 参数值) 。
     *     // 执行导入函数   ExcelUtils.importForExcelData()
     */
}
